/* Bazinga - MPD Jukebox
 * Copyright (C) 2010 m3Soft (Martin Sieke, Matthias Sieke, Matthias Bockstegers)
 * 
 * This program is distributed under the terms of the GNU General Public License.
 * You can redistribute  and/or modify it under the terms of the GNU General Public License 
 * as published by the Free Software Foundation, either version 3 of the License, 
 * or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; 
 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
 * See the GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License along with this program.  
 * If not, see http://www.gnu.org/licenses
 */

package de.m3soft.bazinga;

import java.awt.Toolkit;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.UnknownHostException;
import java.util.Scanner;

import javax.swing.UIManager;

import org.bff.javampd.MPD;
import org.bff.javampd.MPDPlayer;
import org.bff.javampd.exception.MPDConnectionException;
import org.bff.javampd.exception.MPDDatabaseException;
import org.bff.javampd.exception.MPDException;
import org.bff.javampd.exception.MPDPlayerException;
import org.bff.javampd.exception.MPDPlaylistException;

public class Bazinga {
	public static String url;

	public static int port;

	public static String password;

	private static SortedProperties properties;

	private static MPD mpd = null;

	private static BazingaGUI gui = null;

	private static Methoden m = null;

	public static int propertyCount = 14;

	public static void main(String[] args) {

		if (args.length != 0 && (args[0].equalsIgnoreCase("setup") || args[0].equalsIgnoreCase("--setup") || args[0].equalsIgnoreCase("-setup"))) {
			setUp();
			System.exit(0);
		}

		initProperties();

		initMPD();

		initGUI();

		m = new Methoden(mpd, gui, properties);

		new Listener(gui, m);

		gui.setMethoden(m);
		gui.setWindowSize();
		gui.searchSong("");
		gui.setVisible(true);

		// start playing
		try {
			if (!m.getSongList().isEmpty()) {
				if (!m.getMPD().getStatus().equals(MPDPlayer.PlayerStatus.STATUS_PLAYING)) {
					//m.play();
				}
				gui.updatePlaylist();
				gui.updateState(m.getPlayer().getCurrentSong());
				gui.updateAlbumArt(m.getArtist(m.getPlayer().getCurrentSong()).getName(), m.getAlbum(m.getPlayer().getCurrentSong()).getName());
			}
		} catch (MPDPlayerException e) {
			System.out.println("MPDPlayerException while trying to start playing.");
		} catch (MPDConnectionException e) {
			System.out.println("MPDConnectionException while trying to start playing.");
		} catch (MPDException e) {
			System.out.println("MPDException while trying to start playing.");
		}
	}

	private static void initGUI() {
		String theme = properties.getProperty("theme");

		try {
			if (theme.equals("acryl"))
				UIManager.setLookAndFeel("com.jtattoo.plaf.acryl.AcrylLookAndFeel");
			else if (theme.equals("aero"))
				UIManager.setLookAndFeel("com.jtattoo.plaf.aero.AeroLookAndFeel");
			else if (theme.equals("aluminium"))
				UIManager.setLookAndFeel("com.jtattoo.plaf.aluminium.AluminiumLookAndFeel");
			else if (theme.equals("bernstein"))
				UIManager.setLookAndFeel("com.jtattoo.plaf.bernstein.BernsteinLookAndFeel");
			else if (theme.equals("fast"))
				UIManager.setLookAndFeel("com.jtattoo.plaf.fast.FastLookAndFeel");
			else if (theme.equals("hifi"))
				UIManager.setLookAndFeel("com.jtattoo.plaf.hifi.HiFiLookAndFeel");
			else if (theme.equals("mcwin"))
				UIManager.setLookAndFeel("com.jtattoo.plaf.mcwin.McWinLookAndFeel");
			else if (theme.equals("mint"))
				UIManager.setLookAndFeel("com.jtattoo.plaf.mint.MintLookAndFeel");
			else if (theme.equals("noire"))
				UIManager.setLookAndFeel("com.jtattoo.plaf.noire.NoireLookAndFeel");
			else if (theme.equals("smart"))
				UIManager.setLookAndFeel("com.jtattoo.plaf.smart.SmartLookAndFeel");
			else if (theme.equals("luna"))
				UIManager.setLookAndFeel("com.jtattoo.plaf.luna.LunaLookAndFeel");
			else if (theme.equals("gtk"))
				UIManager.setLookAndFeel("com.sun.java.swing.plaf.gtk.GTKLookAndFeel");

		} catch (Exception e) {
			System.out.println("Exception while trying to initialize the GUI.");
			System.exit(-1);
		}

		try {
			gui = new BazingaGUI(mpd);
			gui.setIconImage(Toolkit.getDefaultToolkit().getImage("img/icon.png"));
		} catch (MPDDatabaseException e) {
			System.out.println("MPDDatabaseException while trying to initialize the GUI.");
			System.exit(-1);
		} catch (MPDPlaylistException e) {
			System.out.println("MPDPlaylistException while trying to initialize the GUI.");
			System.exit(-1);
		} catch (MPDPlayerException e) {
			System.out.println("MPDPlayerException while trying to initialize the GUI.");
			System.exit(-1);
		} catch (UnknownHostException e) {
			System.out.println("UnknownHostException while trying to initialize the GUI.");
			System.exit(-1);
		} catch (MPDConnectionException e) {
			System.out.println("MPDConnectionException while trying to initialize the GUI.");
			System.exit(-1);
		} catch (MPDException e) {
			System.out.println("MPDException while trying to initialize the GUI.");
			System.exit(-1);
		}
		gui.setResizable(true);
	}

	private static void initMPD() {
		url = properties.getProperty("url");
		try {
			port = Integer.parseInt(properties.getProperty("port")) + 0;
		} catch (NumberFormatException e) {
			System.out.println("Error reading port. Check file bazinga.cfg");
			System.exit(-1);
		}
		password = properties.getProperty("password");

		try {
			if (password.equals("") || password.isEmpty()) {
				mpd = new MPD(url, port);
			}
			else {
				mpd = new MPD(url, port, password);
			}
			mpd.getMPDPlayer().setXFade(Integer.parseInt(properties.getProperty("crossfade")) + 0);
		} catch (UnknownHostException e) {
			outl("Error connecting to host:\n" + url + ":" + port);
			System.exit(-1);
		} catch (MPDConnectionException e) {
			outl("Error connecting to MPD! Check \"bazinga.cfg\" and \"/etc/mpd.conf\" on host.");
			System.exit(-1);
		} catch (MPDPlayerException e) {
			outl("Error connecting to MPD! Check \"bazinga.cfg\" and \"/etc/mpd.conf\" on host.");
			System.exit(-1);
		}
	}

	private static void initProperties() {
		properties = new SortedProperties();
		String[][] defaultcfg = { { "BoundsX", "BoundsY", "adminPass", "crossfade", "libnotify", "maxTrackTime", "maxTracks", "maxTracksPerAlbum", "maxTracksPerArtist", "password", "port", "theme", "url" }, { "1024", "768", "admin", "0", "true", "300", "20", "3", "2", "", "6600", "aluminium", "localhost" } };

		FileInputStream Inputstream;

		try {
			Inputstream = new FileInputStream("bazinga.cfg");
			properties.load(Inputstream);
			Inputstream.close();
		} catch (FileNotFoundException e) {
			System.out.println("bazinga.cfg was not Found. Try running with option \"setup\".");
			System.exit(-1);
		} catch (IOException e) {
			System.out.println("IOEXeption on reading bazinga.cfg. Try running with option \"setup\".");
			System.exit(-1);
		}

		for (int i = 0; i < defaultcfg[0].length; i++) {
			if (properties.getProperty(defaultcfg[0][i]).isEmpty() && !defaultcfg[0][i].equals("password")) {
				System.out.println("There is a problem with the config file (bazinga.cfg)! \nTry running with option \"setup\".");
				System.exit(-1);
			}
		}
	}

	private static void setUp() {
		String key, value, temp;
		String[][] defaultcfg = { { "BoundsX", "BoundsY", "adminPass", "crossfade", "libnotify", "master", "maxTrackTime", "maxTracks", "maxTracksPerAlbum", "maxTracksPerArtist", "password", "port", "theme", "url" }, { "1024", "768", "admin", "0", "true", "true", "300", "20", "3", "2", "", "6600", "aluminium", "localhost" } };
		properties = new SortedProperties();

		clear();

		if (!eingabe("Are you sure you want to reconfigure the config file? (y/n)").equals("y")) {
			System.exit(0);
		}

		clear();

		eingabe("Welcome to the MPDJukebox setup helper! \nThe essential Properties are now beeing set, \nso please type in Anwers to the following questions, \nor just press ENTER (twice!) to leave default value. \nPress ENTER (twice!) now to begin... \n");

		for (int i = 0; i < defaultcfg[0].length; i++) {
			key = defaultcfg[0][i];
			value = defaultcfg[1][i];
			temp = "";
			clear();
			if (key.equals("adminPass")) {
				temp = eingabe("\nPlease type Admin-Password: \nthis password has to be entered to skip tracks or remove them etc.\n(default: " + value + ")");
				if (temp.equals(""))
					temp = value;
				properties.setProperty(key, temp);
			}
			else if (key.equals("theme")) {
				temp = eingabe(key + "\nselect the theme \npossible values are: acryl, aero, aluminium, bernstein, fast, hifi, mcwin, mint, noire, smart, luna, gtk \n(default: " + value + ")");
				if (temp.equals(""))
					temp = value;
				properties.setProperty(key, temp);
			}
			else if (key.equals("master")) {
				temp = eingabe(key + "\nif Bazinga is running only once, you can leave default. Otherwise, there should only be one master-Bazinga (true) and as many slave-Bazingas (false) as you like. \npossible values are: true and false \n(default: " + value + ")");
				if (temp.equals(""))
					temp = value;
				properties.setProperty(key, temp);
			}
			else if (key.equals("BoundsX")) {
				temp = eingabe(key + "\nWindow width of Bazinga when it is started \n(default: " + value + ")");
				if (temp.equals(""))
					temp = value;
				properties.setProperty(key, temp);
			}
			else if (key.equals("BoundsY")) {
				temp = eingabe(key + "\nWindow height of Bazinga when it is started \n(default: " + value + ")");
				if (temp.equals(""))
					temp = value;
				properties.setProperty(key, temp);
			}
			else if (key.equals("libnotify")) {
				temp = eingabe(key + "\nmessage output via libnotify. the packet \"libnotify-bin\" is required! \n(default: " + value + ")");
				if (temp.equals(""))
					temp = value;
				properties.setProperty(key, temp);
			}
			else if (key.equals("maxTrackTime")) {
				temp = eingabe(key + "\nMaximum time in seconds, after Bazinga skips to next track\n(default: " + value + ")");
				if (temp.equals(""))
					temp = value;
				properties.setProperty(key, temp);
			}
			else if (key.equals("maxTracks")) {
				temp = eingabe(key + "\nMaximum number of tracks in playlist\n(default: " + value + ")");
				if (temp.equals(""))
					temp = value;
				properties.setProperty(key, temp);
			}
			else if (key.equals("maxTracksPerAlbum")) {
				temp = eingabe(key + "\nMaximum number of tracks per album in playlist\n(default: " + value + ")");
				if (temp.equals(""))
					temp = value;
				properties.setProperty(key, temp);
			}
			else if (key.equals("maxTracksPerArtist")) {
				temp = eingabe(key + "\nMaximum number of tracks per artist in playlist\n(default: " + value + ")");
				if (temp.equals(""))
					temp = value;
				properties.setProperty(key, temp);
			}
			else if (key.equals("password")) {
				temp = eingabe(key + "\nPassword of mpd server (see /etc/mpd.conf)\n(default: " + value + ")");
				if (temp.equals(""))
					temp = value;
				properties.setProperty(key, temp);
			}
			else if (key.equals("port")) {
				temp = eingabe(key + "\nport of mpd server (see /etc/mpd.conf)\n(default: " + value + ")");
				if (temp.equals(""))
					temp = value;
				properties.setProperty(key, temp);
			}
			else if (key.equals("url")) {
				temp = eingabe(key + "\nurl of mpd server (see /etc/mpd.conf)\n(default: " + value + ")");
				if (temp.equals(""))
					temp = value;
				properties.setProperty(key, temp);
			} else {
				temp = eingabe(key + ": \n(default: " + value + ")");
				if (temp.equals("") || temp.equals("\n"))
					temp = value;
				properties.setProperty(key, temp);
			}
		}
		clear();
		FileOutputStream outstream;
		try {
			outstream = new FileOutputStream("bazinga.cfg");
			properties.store(outstream, null);
			outstream.close();
		} catch (FileNotFoundException ex) {
			System.out.println("bazinga.cfg was not Found. Try running with option \"setup\".");
			System.exit(-1);
		} catch (IOException ex) {
			System.out.println("IOEXeption on reading bazinga.cfg. Try running with option \"setup\".");
			System.exit(-1);
		}
		eingabe("That's it! If you encounter problems, run setup again, \nor alter config file manually.");
		clear();
	}

	private static String eingabe(String ausgabe) {
		outl(ausgabe);
		@SuppressWarnings("resource")
		Scanner s = new Scanner(System.in);
		String tempString;
		s.useDelimiter("\n");
		try {
			tempString = s.next();
		} catch (Exception InputMismatchException) {
			outl("Wrong input, please try again!");
			return eingabe(ausgabe);
		}
		if (tempString.contains(" ")) {
			outl("Wrong input, please try again!");
			return eingabe(ausgabe);
		}
		return tempString;
	}

	private static void outl(String text) {
		System.out.println(text);
	}

	private static void clear() {
		for (int i = 0; i < 50; i++)
			outl("");
	}
}
